import com.google.gson.Gson
import java.awt.Panel
import java.io.File
import java.lang.Exception
import java.text.SimpleDateFormat
import java.util.*
import javax.swing.*


/**
 * 主窗口
 */
class MainWindow : JFrame(), Runnable
{
    private val gson = Gson()
    private val configFile = File(".apkSignConfig.txt")
    private var config: ApkSignConfig

    private val contentPanel by lazy { Panel() }
    private val formater = SimpleDateFormat("YYYY-MM-dd HH:mm:ss")

    init
    {
        // 读取配置文件
        config = if (!configFile.exists())
        {
            configFile.createNewFile()
            ApkSignConfig()
        } else
        {
            val jsonStr = configFile.reader().readText()
            gson.fromJson(jsonStr, ApkSignConfig::class.java) ?: ApkSignConfig()
        }
    }

    /**
     * 初始化窗口
     */
    private fun initWindow()
    {
        setDefaultLookAndFeelDecorated(true)
        title = "ApkSign-安卓签名"
        setSize(800, 490)
        setLocationRelativeTo(null)
        defaultCloseOperation = JFrame.EXIT_ON_CLOSE
        isResizable = false
        isVisible = true
    }

    /**
     * 初始化面板
     */
    private fun initPanel()
    {
        contentPane = contentPanel
        contentPanel.layout = null
    }

    /**
     * 初始化布局
     */
    private fun initLayout()
    {
        // 组件高度
        val componentHeight = 40
        // 标签宽度
        val labelWidth = 150
        // 选择按钮的宽度
        val btnWidth = 100

        // buildToolPath
        val buildToolLabel = JLabel("Build-Tools 目录:")
        buildToolLabel.setBounds(0, componentHeight * 0, labelWidth, componentHeight)
        contentPanel.add(buildToolLabel)
        val buildToolTextField = JTextField(config.buildToolPath)
        buildToolTextField.setBounds(labelWidth, componentHeight * 0, 800 - labelWidth - btnWidth, componentHeight)
        contentPanel.add(buildToolTextField)
        val buildToolButton = JButton("请选择")
        buildToolButton.setBounds(800 - btnWidth, componentHeight * 0, btnWidth, componentHeight)
        buildToolButton.addActionListener {
            choseFile(JFileChooser.DIRECTORIES_ONLY) {
                buildToolTextField.text = "$it"
            }
        }
        contentPanel.add(buildToolButton)


        // jksPath
        val jksPathLabel = JLabel("签名文件:")
        jksPathLabel.setBounds(0, componentHeight * 1, labelWidth, componentHeight)
        contentPanel.add(jksPathLabel)
        val jksPathTextField = JTextField(config.jksPath)
        jksPathTextField.setBounds(labelWidth, componentHeight * 1, 800 - labelWidth - btnWidth, componentHeight)
        contentPanel.add(jksPathTextField)
        val jksPathButton = JButton("请选择")
        jksPathButton.setBounds(800 - btnWidth, componentHeight * 1, btnWidth, componentHeight)
        // 选择文件
        jksPathButton.addActionListener {
            choseFile(JFileChooser.FILES_ONLY) {
                jksPathTextField.text = "$it"
            }
        }
        contentPanel.add(jksPathButton)

        // jksPasswd
        val jksPasswdLabel = JLabel("签名文件密码:")
        jksPasswdLabel.setBounds(0, componentHeight * 2, labelWidth, componentHeight)
        contentPanel.add(jksPasswdLabel)
        val jksPasswdTextField = JTextField(config.jksPasswd)
        jksPasswdTextField.setBounds(labelWidth, componentHeight * 2, 800 - labelWidth, componentHeight)
        contentPanel.add(jksPasswdTextField)

        // alias
        val aliasLabel = JLabel("签名别名:")
        aliasLabel.setBounds(0, componentHeight * 3, labelWidth, componentHeight)
        contentPanel.add(aliasLabel)
        val aliasTextField = JTextField(config.alias)
        aliasTextField.setBounds(labelWidth, componentHeight * 3, 800 - labelWidth, componentHeight)
        contentPanel.add(aliasTextField)

        // aliasPass
        val aliasPassLabel = JLabel("别名密码:")
        aliasPassLabel.setBounds(0, componentHeight * 4, labelWidth, componentHeight)
        contentPanel.add(aliasPassLabel)
        val aliasPassTextField = JTextField(config.aliasPass)
        aliasPassTextField.setBounds(labelWidth, componentHeight * 4, 800 - labelWidth, componentHeight)
        contentPanel.add(aliasPassTextField)

        // unSignApkFile
        val unSignApkFilePassLabel = JLabel("待签名Apk:")
        unSignApkFilePassLabel.setBounds(0, componentHeight * 5, labelWidth, componentHeight)
        contentPanel.add(unSignApkFilePassLabel)
        val unSignApkFileTextField = JTextField(config.unSignApkFile)
        unSignApkFileTextField.setBounds(labelWidth, componentHeight * 5, 800 - labelWidth - btnWidth, componentHeight)
        contentPanel.add(unSignApkFileTextField)
        val unSignApkButton = JButton("请选择")
        unSignApkButton.setBounds(800 - btnWidth, componentHeight * 5, btnWidth, componentHeight)

        unSignApkButton.addActionListener {
            choseFile(JFileChooser.FILES_ONLY) {
                unSignApkFileTextField.text = "$it"
            }
        }

        contentPanel.add(unSignApkButton)

        // signApkFile
        val signApkFilePassLabel = JLabel("输出目录:")
        signApkFilePassLabel.setBounds(0, componentHeight * 6, labelWidth, componentHeight)
        contentPanel.add(signApkFilePassLabel)
        val signApkFileTextField = JTextField(config.signApkDir)
        signApkFileTextField.setBounds(labelWidth, componentHeight * 6, 800 - labelWidth - btnWidth, componentHeight)
        contentPanel.add(signApkFileTextField)
        val signApkButton = JButton("请选择")
        signApkButton.setBounds(800 - btnWidth, componentHeight * 6, btnWidth, componentHeight)

        signApkButton.addActionListener {
            choseFile(JFileChooser.DIRECTORIES_ONLY) {
                signApkFileTextField.text = "$it"
            }
        }

        contentPanel.add(signApkButton)


        // startBtn
        val startBtnFilePassLabel = JButton("开始签名")
        startBtnFilePassLabel.setBounds(0, componentHeight * 7, 800, componentHeight)
        contentPanel.add(startBtnFilePassLabel)

        // copyRight
        val copyRightPassLabel = JLabel("QQ群 : 559259945")
        copyRightPassLabel.horizontalAlignment = SwingConstants.CENTER
        copyRightPassLabel.setBounds(0, componentHeight * 8, 800, componentHeight)
        contentPanel.add(copyRightPassLabel)

        // resultLabel
        val resultPanel = JScrollPane()
        resultPanel.setBounds(0, componentHeight * 9, 800, 100)
        val resultArea = JTextArea()
        resultArea.isEditable = false
        resultArea.setBounds(0, 0, 800, 100)
        resultPanel.setViewportView(resultArea)
        contentPanel.add(resultPanel)

        startBtnFilePassLabel.addActionListener {
            val buildToolsPath = buildToolTextField.text
            val jksPath = jksPathTextField.text
            val alias = aliasTextField.text
            val jksPasswd = jksPasswdTextField.text
            val aliasPass = aliasPassTextField.text
            val signApkDir = signApkFileTextField.text
            val unSignApkFile = unSignApkFileTextField.text

            when
            {
                buildToolsPath.isEmpty() || !File(buildToolsPath).exists() ->
                {
                    JOptionPane.showMessageDialog(contentPanel, "请选择编译路径", "错误", JOptionPane.ERROR_MESSAGE)
                }
                jksPath.isEmpty() || !File(jksPath).exists() ->
                {
                    JOptionPane.showMessageDialog(contentPanel, "请选择签名文件", "错误", JOptionPane.ERROR_MESSAGE)
                }
                jksPasswd.isEmpty() ->
                {
                    JOptionPane.showMessageDialog(contentPanel, "请输入签名文件密码", "错误", JOptionPane.ERROR_MESSAGE)
                }
                alias.isEmpty() ->
                {
                    JOptionPane.showMessageDialog(contentPanel, "请输入签名别名", "错误", JOptionPane.ERROR_MESSAGE)
                }
                aliasPass.isEmpty() ->
                {
                    JOptionPane.showMessageDialog(contentPanel, "请输入签名别名密码", "错误", JOptionPane.ERROR_MESSAGE)
                }
                unSignApkFile.isEmpty() || !File(unSignApkFile).exists() || !unSignApkFile.endsWith("apk", true) ->
                {
                    JOptionPane.showMessageDialog(contentPanel, "请选择待签名的apk文件", "错误", JOptionPane.ERROR_MESSAGE)
                }
                signApkDir.isEmpty() || !File(signApkDir).exists() || !File(signApkDir).isDirectory ->
                {
                    JOptionPane.showMessageDialog(contentPanel, "请选择正确的输出目录", "错误", JOptionPane.ERROR_MESSAGE)
                }
                else ->
                {
                    // 保存配置文件
                    config.buildToolPath = buildToolsPath
                    config.jksPath = jksPath
                    config.alias = alias
                    config.jksPasswd = jksPasswd
                    config.aliasPass = aliasPass
                    config.signApkDir = signApkDir
                    config.unSignApkFile = unSignApkFile
                    val jsonStr = gson.toJson(config)
                    configFile.writeText(jsonStr)

                    sign(
                        resultArea,
                        buildToolsPath,
                        jksPath,
                        alias,
                        jksPasswd,
                        aliasPass,
                        File(signApkDir, "sign_${File(unSignApkFile).name}").path,
                        unSignApkFile
                    )
                }
            }
        }
    }

    /**
     * 选择文件
     */
    private fun choseFile(mode: Int = JFileChooser.FILES_AND_DIRECTORIES, onChose: (File) -> Unit)
    {
        val chooser = JFileChooser()
        chooser.fileSelectionMode = mode
        chooser.showDialog(JLabel(), "请选择")
        chooser.selectedFile?.let(onChose)
    }

    /**
     * 签名
     * @param buildToolsPath 编译路径
     * @param jksPath 签名文件
     * @param alias 别名
     * @param ksPass 文件密码
     * @param keyPass 别名密码
     * @param outPath 输出文件
     * @param inPath 输入文件
     */
    private fun sign(
        resultArea: JTextArea,
        buildToolsPath: String,
        jksPath: String,
        alias: String,
        ksPass: String,
        keyPass: String,
        outPath: String,
        inPath: String
    )
    {
        val systemProps = System.getProperties()
        val osName = systemProps["os.name"] as? String?
        val extension = when
        {
            osName?.contains("WIN", true) ?: false -> ".bat"
            else -> ""
        }
        val cmd = "$buildToolsPath/apksigner$extension sign  " +
                "--ks $jksPath  " +
                "--ks-key-alias $alias  " +
                "--ks-pass pass:$ksPass  " +
                "--key-pass pass:$keyPass  " +
                "--out $outPath  $inPath"
        var process: Process? = null
        try
        {
            process = Runtime.getRuntime().exec(cmd)
            val normalResult = process.inputStream.reader().readText()
            val errorResult = process.errorStream.reader().readText()
            when
            {
                normalResult.isNotEmpty() ->
                {
                    resultArea.append("\n${formater.format(Date())}\t$normalResult")
                }
                errorResult.isNotEmpty() ->
                {
                    resultArea.append("\n${formater.format(Date())}\t$errorResult")
                }
                else ->
                {
                    resultArea.append("\n${formater.format(Date())}\t签名成功:$outPath")
                }
            }
        } catch (e: Exception)
        {
            resultArea.append("\n${formater.format(Date())}\t$e")
        } finally
        {
            process?.destroy()
        }
    }
    
    override fun run()
    {
        initWindow()
        initPanel()
        initLayout()
    }
}